import { Setups,BODYPART_COST,BODYPART_ABILITY,BODYPART_ABILITY_Map } from "./setups";
export * from "./setups"

export class BodySetup
{
    static GetCreepCount( BodyLimit:ICreepBody,PatternCountLimit:number,MaxEnergy:number)
    {
        let roomLimitEnergy = MaxEnergy;
        let count = BodySetup.CalRepeatCount(BodyLimit, roomLimitEnergy);
        if(count == 0)
        {
            return 1;
        }
        let CreepCount = PatternCountLimit % count == 0 ? PatternCountLimit / count : Math.ceil(PatternCountLimit / count);

        return CreepCount?CreepCount:1;

    }

	// static FindCreepRoleBody(roleName:RoleName,boost?:BoostLevel): ICreepBody|undefined
	// {
    //     if(Setups[roleName][0].Role == roleName)
    //     {
    //         if(boost && Setups[roleName][boost])
    //         {
    //             return Setups[roleName][boost];
    //         }

    //         return Setups[roleName][0];
    //     }
	// 	// for( const key in Setups)
	// 	// {
    //     //     if(Setups[key][0].Role == roleName)
    //     //     {
    //     //         if(boost && Setups[key][boost])
    //     //         {
    //     //             return Setups[key][boost];
    //     //         }

    //     //         return Setups[key][0];
    //     //     }
	// 	// }
	// 	return undefined;
	// }


	static   CreateBody( creepcontext:ICreepBody, nMaxEnergy:number,controllerlevel?:number):Array<BodyPartConstant>
	{
		let constbody:{ [key: string]: number } = creepcontext.constbody;

		// 1.先计算body。
		let npatternenergy = BodySetup.PatternEnergyCost(creepcontext.pattern);

		let nconstCostenergy =  BodySetup.PatternEnergyCost(constbody);
		// 1.1能量限制的Body数量
		let nRepeatPatternCount =Math.floor( (nMaxEnergy-nconstCostenergy) / npatternenergy);
        // 1.2配置限制数量
        nRepeatPatternCount = Math.min(creepcontext.patterncount,nRepeatPatternCount);
		if(controllerlevel && creepcontext.specialpattern[controllerlevel])
		{
			// 如果有指定等级限制的模式数量。则以等级限制为准
			nRepeatPatternCount =creepcontext.specialpattern[controllerlevel];
		}
		// 1.2最大body数量限制的Body数量
        const constbodycount = BodySetup.PatternBodyCount(creepcontext.constbody)
		let nMaxPatternCount =Math.floor((50 -constbodycount) / BodySetup.PatternBodyCount(creepcontext.pattern));

		nRepeatPatternCount =Math.min(nRepeatPatternCount,nMaxPatternCount);
		let bodys:Array<BodyPartConstant> = new Array<BodyPartConstant>();
		if(nRepeatPatternCount<=0)
		{
			global.Log.Info( `孵化能量 ${nMaxEnergy} Error->孵化模式数量为不大于0 `);
			return bodys;
		}
		// 2.以后有时间了再来按照body的顺序排序body
        let move_count = 0;
        for (let key in constbody)
		{

            if(key =="move")
            {
                move_count+=constbody[key];
            }
            else
            {
                let tmpbody = new Array<BodyPartConstant>(constbody[key]);
                _.fill(tmpbody, key as BodyPartConstant);

                bodys = bodys.concat(tmpbody);
            }

		}

		for (let key in creepcontext.pattern)
		{

            if(key =="move")
            {
                move_count+=creepcontext.pattern[key]*nRepeatPatternCount;
            }
            else
            {
                let tmpbody = new Array<BodyPartConstant>(creepcontext.pattern[key]*nRepeatPatternCount);
                _.fill(tmpbody, key as BodyPartConstant);
                bodys = bodys.concat(tmpbody);
            }
		}

        const insertpad = Math.floor(bodys.length/move_count);
        for(let i=bodys.length;i>=0&& move_count>0;i-=(insertpad),move_count--)
        {
            bodys.splice(i,0,"move");
        }
		return bodys;
	}
	static GetTaskCount(ObjectID:string,BodyLimit:ICreepBody,PatternCountLimit:number,WorkRange=1)
    {
        const Obj = Game.getObjectById<RoomObject&_HasId>(ObjectID as any);
        if(Obj && Obj.room)
        {

            let roomLimitEnergy = Obj.room.energyCapacityAvailable;
            let count = BodySetup.CalRepeatCount(BodyLimit, roomLimitEnergy);
            if(count == 0)
            {
                return 1;
            }

            let CreepCount = PatternCountLimit % count == 0 ? PatternCountLimit / count : Math.ceil(PatternCountLimit / count);
            let pos = Obj.pos;

            let freecount = pos.getFreeSpace(WorkRange).length;

            CreepCount = Math.min(CreepCount,freecount);

            return CreepCount;
        }
        return 0;
    }
	static CalRepeatCount(BodyLimit:{pattern: { [key: string]: number },constbody: { [key: string]: number }},nEnergyLimit:number)
	{
		let constcost = BodySetup.PatternEnergyCost(BodyLimit.constbody);
		let energycost = BodySetup.PatternEnergyCost(BodyLimit.pattern);
		let ncount =Math.floor( (nEnergyLimit-constcost) / energycost);
		if(ncount<=0)
		{
			return 0;
		}
		return ncount;
	}
	private static CalPatternCount( pattern: { [key: string]: number }, nEnergyLimit:number):number
        {
		    let energycost = BodySetup.PatternEnergyCost(pattern);
		    let ncount =Math.floor( nEnergyLimit / energycost);
		    return ncount;
	    }
	/**
	 * @param creeppattern creep body 模式
	 * @param LimitEnergy 能量限制,最多能有多少能量
	*/
	static MaxAliableEnergyCost( creeppattern:ICreepBody, LimitEnergy:number,level:number=0):number
	{
		const constenergy =     BodySetup.PatternEnergyCost(creeppattern.constbody);
		let lesscount = BodySetup.CalPatternCount(creeppattern.pattern,LimitEnergy-constenergy);
        let patterncount = creeppattern.patterncount;
        if(level && creeppattern.specialpattern[level])
        {
            patterncount= creeppattern.specialpattern[level];
        }
		lesscount =Math.min(patterncount,lesscount);


		return constenergy+BodySetup.PatternEnergyCost(creeppattern.pattern)*lesscount;
	}
	static  PatternEnergyCost(pattern: { [key: string]: number }): number
	{
		let energy = 0;
		for (let key in pattern)
		{
			energy += BODYPART_COST[key] * pattern[key];
		}
		return energy;
	}
    static  BodyEnergyCost(body:BodyPartConstant[]): number
	{
		let energy = 0;
		for (const e of body)
		{
			energy += BODYPART_COST[e] ;
		}
		return energy;
	}
	static  PatternBodyCount(pattern: { [key: string]: number }): number
	{
		let count = 0;
		for (let key in pattern)
		{
			count +=   pattern[key];
		}
		return count;
	}
	static GetBodyAbility(bodyName:BodyPartConstant,abilityName:BODYPART_ABILITY,action:string,body:BodyPartDefinition[],ingore_0hitpart=true):number
	{
	  const boostMap:{[boost:string]:{
		  [action:string]:number
	  }}=BOOSTS[bodyName];

	  const bodyability = BODYPART_ABILITY_Map[abilityName];
      let attackbodys
      if(ingore_0hitpart)
      {
         attackbodys =   _.filter(body,item=>item.type == bodyName && item.hits>0);
      }
      else
      {
         attackbodys =   _.filter(body,item=>item.type == bodyName);
      }

	  const damage = _.sum(_.map(attackbodys,item=>
		  {
			  if(item.boost && boostMap[item.boost][action])
			  {
				  return     boostMap[item.boost][action]*bodyability;
			  }
			  return bodyability;
		  }))
	  return damage;
	}
}
